@@ -0,0 +1,5 @@  | 
            ||
| 1 | 
                +* ``Refresh Cache`` => ``Delete Cache``  | 
            |
| 2 | 
                +* Remove GROUP_USERS_XXX_SET ?  | 
            |
| 3 | 
                +* ``get_group_info`` vs. ``group.data``  | 
            |
| 4 | 
                +* Docstring simplify  | 
            |
| 5 | 
                +* ``admin_id`` vs. ``user_id`  | 
            
                @@ -5,7 +5,7 @@ from __future__ import division  | 
            ||
| 5 | 5 | 
                from django.conf import settings  | 
            
| 6 | 6 | 
                from logit import logit  | 
            
| 7 | 7 | 
                 | 
            
| 8 | 
                -from account.models import TourGuideInfo  | 
            |
| 8 | 
                +from account.models import TourGuideInfo, UserInfo  | 
            |
| 9 | 9 | 
                from utils.error.errno_utils import TourGuideStatusCode  | 
            
| 10 | 10 | 
                from utils.error.response_utils import response  | 
            
| 11 | 11 | 
                 | 
            
                @@ -37,7 +37,7 @@ def tourguide_submit_api(request):  | 
            ||
| 37 | 37 | 
                }  | 
            
| 38 | 38 | 
                 | 
            
| 39 | 39 | 
                tourguide, created = TourGuideInfo.objects.get_or_create(unionid=unionid, defaults=fields)  | 
            
| 40 | 
                - # 状态为 UNVERIFIED 的允许修改, 其他需要登录摄影师 APP 进行信息的修改  | 
            |
| 40 | 
                + # 状态为 UNVERIFIED 的允许修改, 其他需要登录导游 APP 进行信息的修改  | 
            |
| 41 | 41 | 
                if tourguide.user_status not in [TourGuideInfo.UNVERIFIED, TourGuideInfo.REFUSED]:  | 
            
| 42 | 42 | 
                return response(TourGuideStatusCode.TOURGUIDE_ALREADY_NOT_UNVERIFIED)  | 
            
| 43 | 43 | 
                if not created:  | 
            
                @@ -46,3 +46,35 @@ def tourguide_submit_api(request):  | 
            ||
| 46 | 46 | 
                tourguide.save()  | 
            
| 47 | 47 | 
                 | 
            
| 48 | 48 | 
                     return response(200, 'Submit Success', u'提交成功', {})
               | 
            
| 49 | 
                +  | 
            |
| 50 | 
                +  | 
            |
| 51 | 
                +@logit  | 
            |
| 52 | 
                +def tourguide_wx_authorize_api(request):  | 
            |
| 53 | 
                +    unionid = request.POST.get('unionid', '')
               | 
            |
| 54 | 
                +    openid = request.POST.get('openid', '')
               | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                +    sex = request.POST.get('sex', 0)
               | 
            |
| 57 | 
                +    nickname = request.POST.get('nickname', '') or request.POST.get('screen_name', '')
               | 
            |
| 58 | 
                +    avatar = request.POST.get('headimgurl', '') or request.POST.get('profile_image_url', '')
               | 
            |
| 59 | 
                +    country = request.POST.get('country', '')
               | 
            |
| 60 | 
                +    province = request.POST.get('province', '')
               | 
            |
| 61 | 
                +    city = request.POST.get('city', '')
               | 
            |
| 62 | 
                +  | 
            |
| 63 | 
                + try:  | 
            |
| 64 | 
                + user = UserInfo.objects.get(unionid=unionid)  | 
            |
| 65 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 66 | 
                + return response(TourGuideStatusCode.TOURGUIDE_NOT_FOUND)  | 
            |
| 67 | 
                +  | 
            |
| 68 | 
                + if user.user_status != UserInfo.ACTIVATED:  | 
            |
| 69 | 
                + return response(TourGuideStatusCode.TOURGUIDE_NOT_ACTIVATED)  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                + user.openid = openid  | 
            |
| 72 | 
                + user.sex = sex  | 
            |
| 73 | 
                + user.nickname = nickname  | 
            |
| 74 | 
                + user.avatar = avatar  | 
            |
| 75 | 
                + user.country = country  | 
            |
| 76 | 
                + user.province = province  | 
            |
| 77 | 
                + user.city = city  | 
            |
| 78 | 
                + user.save()  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + return response(200, 'Tour Guide Login Success', u'导游登录成功', user.data)  | 
            
                @@ -133,7 +133,6 @@ def user_wx_authorize_api(request):  | 
            ||
| 133 | 133 | 
                     province = request.POST.get('province', '')
               | 
            
| 134 | 134 | 
                     city = request.POST.get('city', '')
               | 
            
| 135 | 135 | 
                 | 
            
| 136 | 
                - # 判断 unionid 是否已经存在,如果已经存在,则直接返回改帐户信息  | 
            |
| 137 | 136 | 
                try:  | 
            
| 138 | 137 | 
                user = UserInfo.objects.select_for_update().get(unionid=unionid)  | 
            
| 139 | 138 | 
                except UserInfo.DoesNotExist:  | 
            
                @@ -4,8 +4,9 @@ from django.conf.urls import url  | 
            ||
| 4 | 4 | 
                 | 
            
| 5 | 5 | 
                from account import views as account_views  | 
            
| 6 | 6 | 
                from account import tourguide_views  | 
            
| 7 | 
                +from geo import views as geo_views  | 
            |
| 7 | 8 | 
                from group import views as group_views  | 
            
| 8 | 
                -from group import lensman_views  | 
            |
| 9 | 
                +from group import lensman_views, tourguidegroup_views, tourguidegroupuser_views  | 
            |
| 9 | 10 | 
                from message import views as message_views  | 
            
| 10 | 11 | 
                from operation import views as op_views  | 
            
| 11 | 12 | 
                from pay import views as pay_views  | 
            
                @@ -45,6 +46,8 @@ urlpatterns += [  | 
            ||
| 45 | 46 | 
                # 导游相关  | 
            
| 46 | 47 | 
                urlpatterns += [  | 
            
| 47 | 48 | 
                url(r'^t/submit$', tourguide_views.tourguide_submit_api, name='tourguide_submit_api'), # 导游信息提交  | 
            
| 49 | 
                +  | 
            |
| 50 | 
                + url(r'^t/wx/authorize$', tourguide_views.tourguide_wx_authorize_api, name='tourguide_wx_authorize_api'), # 微信用户授权  | 
            |
| 48 | 51 | 
                ]  | 
            
| 49 | 52 | 
                 | 
            
| 50 | 53 | 
                # 群组相关  | 
            
                @@ -53,14 +56,36 @@ urlpatterns += [  | 
            ||
| 53 | 56 | 
                url(r'^g/detail$', group_views.group_detail_api, name='group_detail_api'), # 群组详情  | 
            
| 54 | 57 | 
                url(r'^g/update$', group_views.group_update_api, name='group_update_api'), # 群组更新  | 
            
| 55 | 58 | 
                url(r'^g/list$', group_views.group_list_api, name='group_list_api'), # 群组列表  | 
            
| 56 | 
                - url(r'^g/join$', group_views.group_join_api, name='group_join_api'), # 申请加群  | 
            |
| 57 | 59 | 
                url(r'^g/lock$', group_views.group_lock_api, name='group_lock_api'), # 群组锁定  | 
            
| 58 | 60 | 
                url(r'^g/unlock$', group_views.group_unlock_api, name='group_unlock_api'), # 群组解锁  | 
            
| 61 | 
                + url(r'^g/data$', group_views.group_data_api, name='group_data_api'), # 群组数据, 评论数, 点赞数  | 
            |
| 62 | 
                +]  | 
            |
| 63 | 
                +  | 
            |
| 64 | 
                +# 群用户相关  | 
            |
| 65 | 
                +urlpatterns += [  | 
            |
| 66 | 
                + url(r'^g/join$', group_views.group_join_api, name='group_join_api'), # 成员申请加群  | 
            |
| 59 | 67 | 
                url(r'^g/remove$', group_views.group_remove_api, name='group_remove_api'), # 成员移除, 管理员主动, 群成员被动  | 
            
| 60 | 68 | 
                url(r'^g/quit$', group_views.group_quit_api, name='group_quit_api'), # 成员退出,群成员主动  | 
            
| 61 | 69 | 
                # url(r'^g/pass$', group_views.group_pass_api, name='group_pass_api'), # 申请通过  | 
            
| 62 | 70 | 
                # url(r'^g/refuse$', group_views.group_refuse_api, name='group_refuse_api'), # 申请拒绝  | 
            
| 63 | 
                - url(r'^g/data$', group_views.group_data_api, name='group_data_api'), # 群组数据, 评论数, 点赞数  | 
            |
| 71 | 
                +]  | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                +# 导游团相关  | 
            |
| 74 | 
                +urlpatterns += [  | 
            |
| 75 | 
                + url(r'^tg/create$', tourguidegroup_views.tg_group_create_api, name='tg_group_create_api'), # 导游团创建  | 
            |
| 76 | 
                + url(r'^tg/detail$', tourguidegroup_views.tg_group_detail_api, name='tg_group_detail_api'), # 导游团详情  | 
            |
| 77 | 
                + url(r'^tg/update$', tourguidegroup_views.tg_group_update_api, name='tg_group_update_api'), # 导游团更新  | 
            |
| 78 | 
                + url(r'^tg/close$', tourguidegroup_views.tg_group_close_api, name='tg_group_close_api'), # 导游团关闭  | 
            |
| 79 | 
                + url(r'^tg/gather/start$', tourguidegroup_views.tg_group_gather_start_api, name='tg_group_gather_start_api'), # 导游团设置集合时间和地点  | 
            |
| 80 | 
                + # url(r'^tg/gather/end$', tourguidegroup_views.tg_group_gather_end_api, name='tg_group_gather_end_api'), # 导游团集合结束,清理数据  | 
            |
| 81 | 
                +]  | 
            |
| 82 | 
                +  | 
            |
| 83 | 
                +# 导游团用户相关  | 
            |
| 84 | 
                +urlpatterns += [  | 
            |
| 85 | 
                + url(r'^tgu/join$', tourguidegroupuser_views.tgu_group_user_join_api, name='tgu_group_user_join_api'), # 导游团用户加群  | 
            |
| 86 | 
                + url(r'^tgu/update$', tourguidegroupuser_views.tgu_group_user_update_api, name='tg_group_update_api'), # 导游团用户更新  | 
            |
| 87 | 
                + url(r'^tgu/locations$', tourguidegroupuser_views.tgu_group_user_locations_api, name='tgu_group_user_locations_api'), # 导游团所有用户位置信息  | 
            |
| 88 | 
                + url(r'^tgu/location$', tourguidegroupuser_views.tgu_group_user_location_api, name='tgu_group_user_location_api'), # 导游团单个用户位置信息  | 
            |
| 64 | 89 | 
                ]  | 
            
| 65 | 90 | 
                 | 
            
| 66 | 91 | 
                # 飞图相关  | 
            
                @@ -107,6 +132,11 @@ urlpatterns += [  | 
            ||
| 107 | 132 | 
                url(r'^op/download$', op_views.download_api, name='download_api'), # 下载接口  | 
            
| 108 | 133 | 
                ]  | 
            
| 109 | 134 | 
                 | 
            
| 135 | 
                +# 地理位置相关  | 
            |
| 136 | 
                +urlpatterns += [  | 
            |
| 137 | 
                + url(r'^geo/submit$', geo_views.geo_submit_api, name='geo_submit_api'), # 地理位置信息提交  | 
            |
| 138 | 
                +]  | 
            |
| 139 | 
                +  | 
            |
| 110 | 140 | 
                # 支付相关  | 
            
| 111 | 141 | 
                urlpatterns += [  | 
            
| 112 | 142 | 
                url(r'^wx/order_create$', pay_views.wx_order_create_api, name='wx_order_create_api'), # 订单创建  | 
            
                @@ -0,0 +1,4 @@  | 
            ||
| 1 | 
                +from django.contrib import admin  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +# Register your models here.  | 
            
                @@ -0,0 +1,4 @@  | 
            ||
| 1 | 
                +from django.db import models  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +# Create your models here.  | 
            
                @@ -0,0 +1,4 @@  | 
            ||
| 1 | 
                +from django.test import TestCase  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +# Create your tests here.  | 
            
                @@ -0,0 +1,38 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from __future__ import division  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +import json  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +from django.conf import settings  | 
            |
| 8 | 
                +from logit import logit  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +from utils.error.errno_utils import GroupUserStatusCode  | 
            |
| 11 | 
                +from utils.error.response_utils import response  | 
            |
| 12 | 
                +from utils.redis.rkeys import (TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_USER_BELONG,  | 
            |
| 13 | 
                + TOUR_GUIDE_GROUP_USER_GEO_LIST)  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +r = settings.REDIS_CACHE  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +@logit  | 
            |
| 20 | 
                +def geo_submit_api(request):  | 
            |
| 21 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 22 | 
                +    longitude = request.POST.get('lon', '')  # 经度
               | 
            |
| 23 | 
                +    latitude = request.POST.get('lat', '')  # 纬度
               | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                + # 获取用户当前所处导游群组  | 
            |
| 26 | 
                + group_id = r.get(TOUR_GUIDE_GROUP_USER_BELONG % user_id)  | 
            |
| 27 | 
                + if not group_id:  | 
            |
| 28 | 
                + return response(GroupUserStatusCode.USER_HAS_NOT_JOIN_GROUP)  | 
            |
| 29 | 
                +  | 
            |
| 30 | 
                + r.geoadd(TOUR_GUIDE_GROUP_GEO_INFO % group_id, longitude, latitude, user_id)  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)  | 
            |
| 33 | 
                +    r.rpush(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), json.dumps({
               | 
            |
| 34 | 
                + 'lon': longitude,  | 
            |
| 35 | 
                + 'lat': latitude,  | 
            |
| 36 | 
                + }))  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + return response(200, 'Geo Info Submit Success', u'地理位置信息上传成功')  | 
            
                @@ -107,7 +107,6 @@ def lensman_wx_authorize_api(request):  | 
            ||
| 107 | 107 | 
                     province = request.POST.get('province', '')
               | 
            
| 108 | 108 | 
                     city = request.POST.get('city', '')
               | 
            
| 109 | 109 | 
                 | 
            
| 110 | 
                - # 判断 unionid 是否已经存在,如果已经存在,则直接返回改帐户信息  | 
            |
| 111 | 110 | 
                try:  | 
            
| 112 | 111 | 
                user = UserInfo.objects.get(unionid=unionid)  | 
            
| 113 | 112 | 
                except UserInfo.DoesNotExist:  | 
            
                @@ -0,0 +1,74 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class Migration(migrations.Migration):  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                + dependencies = [  | 
            |
| 10 | 
                +        ('group', '0023_groupinfo_group_initio'),
               | 
            |
| 11 | 
                + ]  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + operations = [  | 
            |
| 14 | 
                + migrations.AddField(  | 
            |
| 15 | 
                + model_name='groupinfo',  | 
            |
| 16 | 
                + name='ended_at',  | 
            |
| 17 | 
                + field=models.DateTimeField(help_text='\u7ed3\u675f\u65f6\u95f4', null=True, verbose_name='ended_at', blank=True),  | 
            |
| 18 | 
                + ),  | 
            |
| 19 | 
                + migrations.AddField(  | 
            |
| 20 | 
                + model_name='groupinfo',  | 
            |
| 21 | 
                + name='gather_at',  | 
            |
| 22 | 
                + field=models.DateTimeField(help_text='\u96c6\u5408\u65f6\u95f4', null=True, verbose_name='gather_at', blank=True),  | 
            |
| 23 | 
                + ),  | 
            |
| 24 | 
                + migrations.AddField(  | 
            |
| 25 | 
                + model_name='groupinfo',  | 
            |
| 26 | 
                + name='gather_lat',  | 
            |
| 27 | 
                + field=models.FloatField(help_text='\u96c6\u5408\u7eac\u5ea6', null=True, verbose_name='gather_lat', blank=True),  | 
            |
| 28 | 
                + ),  | 
            |
| 29 | 
                + migrations.AddField(  | 
            |
| 30 | 
                + model_name='groupinfo',  | 
            |
| 31 | 
                + name='gather_lon',  | 
            |
| 32 | 
                + field=models.FloatField(help_text='\u96c6\u5408\u7ecf\u5ea6', null=True, verbose_name='gather_lon', blank=True),  | 
            |
| 33 | 
                + ),  | 
            |
| 34 | 
                + migrations.AddField(  | 
            |
| 35 | 
                + model_name='groupinfo',  | 
            |
| 36 | 
                + name='group_closed',  | 
            |
| 37 | 
                + field=models.BooleanField(default=False, help_text='\u7fa4\u7ec4\u5173\u95ed', verbose_name='group_closed'),  | 
            |
| 38 | 
                + ),  | 
            |
| 39 | 
                + migrations.AddField(  | 
            |
| 40 | 
                + model_name='groupinfo',  | 
            |
| 41 | 
                + name='started_at',  | 
            |
| 42 | 
                + field=models.DateTimeField(help_text='\u5f00\u59cb\u65f6\u95f4', null=True, verbose_name='started_at', blank=True),  | 
            |
| 43 | 
                + ),  | 
            |
| 44 | 
                + migrations.AddField(  | 
            |
| 45 | 
                + model_name='groupuserinfo',  | 
            |
| 46 | 
                + name='name',  | 
            |
| 47 | 
                + field=models.CharField(help_text='\u7528\u6237\u59d3\u540d', max_length=255, null=True, verbose_name='name', blank=True),  | 
            |
| 48 | 
                + ),  | 
            |
| 49 | 
                + migrations.AddField(  | 
            |
| 50 | 
                + model_name='groupuserinfo',  | 
            |
| 51 | 
                + name='phone',  | 
            |
| 52 | 
                + field=models.CharField(help_text='\u7528\u6237\u7535\u8bdd', max_length=255, null=True, verbose_name='phone', blank=True),  | 
            |
| 53 | 
                + ),  | 
            |
| 54 | 
                + migrations.AddField(  | 
            |
| 55 | 
                + model_name='groupuserinfo',  | 
            |
| 56 | 
                + name='relative_person',  | 
            |
| 57 | 
                + field=models.IntegerField(default=1, help_text='\u5173\u8054\u4eba\u6570', verbose_name='relative_person'),  | 
            |
| 58 | 
                + ),  | 
            |
| 59 | 
                + migrations.AddField(  | 
            |
| 60 | 
                + model_name='groupuserinfo',  | 
            |
| 61 | 
                + name='remark',  | 
            |
| 62 | 
                + field=models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True),  | 
            |
| 63 | 
                + ),  | 
            |
| 64 | 
                + migrations.AddField(  | 
            |
| 65 | 
                + model_name='groupuserinfo',  | 
            |
| 66 | 
                + name='subadmin',  | 
            |
| 67 | 
                + field=models.BooleanField(default=False, help_text='\u526f\u7fa4\u7ec4\u7ba1\u7406\u5458', verbose_name='subadmin'),  | 
            |
| 68 | 
                + ),  | 
            |
| 69 | 
                + migrations.AlterField(  | 
            |
| 70 | 
                + model_name='groupinfo',  | 
            |
| 71 | 
                + name='group_from',  | 
            |
| 72 | 
                + field=models.IntegerField(default=0, help_text='\u7fa4\u7ec4\u6765\u6e90', verbose_name='group_from', choices=[(0, 'APP \u5efa\u7fa4'), (1, 'SESSION \u5efa\u7fa4'), (10, '\u5bfc\u6e38\u5efa\u7fa4')]),  | 
            |
| 73 | 
                + ),  | 
            |
| 74 | 
                + ]  | 
            
                @@ -17,10 +17,12 @@ r = settings.REDIS_CACHE  | 
            ||
| 17 | 17 | 
                class GroupInfo(CreateUpdateMixin):  | 
            
| 18 | 18 | 
                APP_GROUP = 0  | 
            
| 19 | 19 | 
                SESSION_GROUP = 1  | 
            
| 20 | 
                + TOURGUIDE_GROUP = 10  | 
            |
| 20 | 21 | 
                 | 
            
| 21 | 22 | 
                GROUP_FROM = (  | 
            
| 22 | 23 | 
                (APP_GROUP, u'APP 建群'),  | 
            
| 23 | 24 | 
                (SESSION_GROUP, u'SESSION 建群'),  | 
            
| 25 | 
                + (TOURGUIDE_GROUP, u'导游建群'),  | 
            |
| 24 | 26 | 
                )  | 
            
| 25 | 27 | 
                 | 
            
| 26 | 28 | 
                group_id = models.CharField(_(u'group_id'), max_length=255, blank=True, null=True, help_text=u'群组唯一标识', db_index=True, unique=True)  | 
            
                @@ -33,6 +35,13 @@ class GroupInfo(CreateUpdateMixin):  | 
            ||
| 33 | 35 | 
                session_id = models.CharField(_(u'session_id'), max_length=255, blank=True, null=True, help_text=u'照片组唯一标识', db_index=True)  | 
            
| 34 | 36 | 
                group_lock = models.BooleanField(_(u'group_lock'), default=False, help_text=u'群组锁定')  | 
            
| 35 | 37 | 
                group_initio = models.BooleanField(_(u'group_initio'), default=False, help_text=u'群组查看照片从头开始')  | 
            
| 38 | 
                + # 导游团  | 
            |
| 39 | 
                + started_at = models.DateTimeField(_(u'started_at'), blank=True, null=True, help_text=_(u'开始时间'))  | 
            |
| 40 | 
                + ended_at = models.DateTimeField(_(u'ended_at'), blank=True, null=True, help_text=_(u'结束时间'))  | 
            |
| 41 | 
                + group_closed = models.BooleanField(_(u'group_closed'), default=False, help_text=u'群组关闭')  | 
            |
| 42 | 
                + gather_at = models.DateTimeField(_(u'gather_at'), blank=True, null=True, help_text=_(u'集合时间'))  | 
            |
| 43 | 
                + gather_lon = models.FloatField(_(u'gather_lon'), blank=True, null=True, help_text=_(u'集合经度'))  | 
            |
| 44 | 
                + gather_lat = models.FloatField(_(u'gather_lat'), blank=True, null=True, help_text=_(u'集合纬度'))  | 
            |
| 36 | 45 | 
                 | 
            
| 37 | 46 | 
                class Meta:  | 
            
| 38 | 47 | 
                verbose_name = _(u'groupinfo')  | 
            
                @@ -57,6 +66,11 @@ class GroupInfo(CreateUpdateMixin):  | 
            ||
| 57 | 66 | 
                'group_from': self.group_from,  | 
            
| 58 | 67 | 
                'group_lock': self.group_lock,  | 
            
| 59 | 68 | 
                'group_initio': self.group_initio,  | 
            
| 69 | 
                + 'started_at': self.started_at.replace(microsecond=0),  | 
            |
| 70 | 
                + 'ended_at': self.ended_at.replace(microsecond=0),  | 
            |
| 71 | 
                + 'gather_at': self.gather_at.replace(microsecond=0),  | 
            |
| 72 | 
                + 'gather_lon': self.gather_lon,  | 
            |
| 73 | 
                + 'gather_lat': self.gather_lat,  | 
            |
| 60 | 74 | 
                'created_at': self.created_at.replace(microsecond=0),  | 
            
| 61 | 75 | 
                }  | 
            
| 62 | 76 | 
                 | 
            
                @@ -111,6 +125,12 @@ class GroupUserInfo(CreateUpdateMixin):  | 
            ||
| 111 | 125 | 
                refused_at = models.DateTimeField(_(u'refused_at'), blank=True, null=True, help_text=_(u'拒绝时间'))  | 
            
| 112 | 126 | 
                deleted_at = models.DateTimeField(_(u'deleted_at'), blank=True, null=True, help_text=_(u'删除时间'))  | 
            
| 113 | 127 | 
                quit_at = models.DateTimeField(_(u'quit_at'), blank=True, null=True, help_text=_(u'退出时间'))  | 
            
| 128 | 
                + # 导游团相关  | 
            |
| 129 | 
                + subadmin = models.BooleanField(_(u'subadmin'), default=False, help_text=u'副群组管理员')  | 
            |
| 130 | 
                + name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'用户姓名')  | 
            |
| 131 | 
                + phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'用户电话')  | 
            |
| 132 | 
                + relative_person = models.IntegerField(_(u'relative_person'), default=1, help_text=u'关联人数')  | 
            |
| 133 | 
                + remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')  | 
            |
| 114 | 134 | 
                 | 
            
| 115 | 135 | 
                class Meta:  | 
            
| 116 | 136 | 
                verbose_name = _(u'groupuserinfo')  | 
            
                @@ -126,6 +146,11 @@ class GroupUserInfo(CreateUpdateMixin):  | 
            ||
| 126 | 146 | 
                'nickname': self.nickname,  | 
            
| 127 | 147 | 
                'avatar': self.avatar,  | 
            
| 128 | 148 | 
                'admin': self.admin,  | 
            
| 149 | 
                + 'subadmin': self.subadmin,  | 
            |
| 150 | 
                + 'name': self.name,  | 
            |
| 151 | 
                + 'phone': self.phone,  | 
            |
| 152 | 
                + 'relative_person': self.relative_person,  | 
            |
| 153 | 
                + 'remark': self.remark,  | 
            |
| 129 | 154 | 
                }  | 
            
| 130 | 155 | 
                 | 
            
| 131 | 156 | 
                 | 
            
                @@ -0,0 +1,239 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from __future__ import division  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +import os  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +import shortuuid  | 
            |
| 8 | 
                +from curtail_uuid import CurtailUUID  | 
            |
| 9 | 
                +from django.conf import settings  | 
            |
| 10 | 
                +from django.core.files.storage import default_storage  | 
            |
| 11 | 
                +from logit import logit  | 
            |
| 12 | 
                +from TimeConvert import TimeConvert as tc  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +from account.models import UserInfo  | 
            |
| 15 | 
                +from group.models import GroupInfo, GroupUserInfo  | 
            |
| 16 | 
                +from utils.error.errno_utils import GroupStatusCode, UserStatusCode  | 
            |
| 17 | 
                +from utils.error.response_utils import response  | 
            |
| 18 | 
                +from utils.redis.rgroup import get_group_info, get_group_users_info, set_group_info, set_group_users_info  | 
            |
| 19 | 
                +from utils.redis.rkeys import TOUR_GUIDE_GROUP_CUR_SESSION  | 
            |
| 20 | 
                +from utils.redis.rtourguide import set_tour_guide_own_group  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +r = settings.REDIS_CACHE  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +@logit  | 
            |
| 27 | 
                +def tg_group_create_api(request):  | 
            |
| 28 | 
                + """  | 
            |
| 29 | 
                + 导游团创建  | 
            |
| 30 | 
                + :param request:  | 
            |
| 31 | 
                + :return:  | 
            |
| 32 | 
                + """  | 
            |
| 33 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 34 | 
                +    group_name = request.POST.get('group_name', '')
               | 
            |
| 35 | 
                +    group_default_avatar = int(request.POST.get('group_default_avatar', 0))
               | 
            |
| 36 | 
                +    started_at = request.POST.get('started_at', '')
               | 
            |
| 37 | 
                +    ended_at = request.POST.get('ended_at', '')
               | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + # 用户校验  | 
            |
| 40 | 
                + try:  | 
            |
| 41 | 
                + user = UserInfo.objects.get(user_id=user_id)  | 
            |
| 42 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 43 | 
                + return response(UserStatusCode.USER_NOT_FOUND)  | 
            |
| 44 | 
                +  | 
            |
| 45 | 
                + # 权限校验  | 
            |
| 46 | 
                + if not user.istourguide:  | 
            |
| 47 | 
                + return response(GroupStatusCode.NOT_GROUP_ADMIN)  | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                + # 导游团校验  | 
            |
| 50 | 
                + if GroupInfo.objects.filter(  | 
            |
| 51 | 
                + admin_id=user_id,  | 
            |
| 52 | 
                + group_closed=False,  | 
            |
| 53 | 
                + status=True,  | 
            |
| 54 | 
                + ended_at__gt=tc.utc_datetime(),  | 
            |
| 55 | 
                + ).exists():  | 
            |
| 56 | 
                + return response(GroupStatusCode.COULD_HAVE_ONLY_ONE_ACTIVE_GROUP)  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + # 群组唯一标识  | 
            |
| 59 | 
                + group_id = CurtailUUID.uuid(GroupInfo, 'group_id')  | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                + # 群组记录创建  | 
            |
| 62 | 
                + group = GroupInfo.objects.create(  | 
            |
| 63 | 
                + group_id=group_id,  | 
            |
| 64 | 
                + admin_id=user_id,  | 
            |
| 65 | 
                + group_name=group_name,  | 
            |
| 66 | 
                + group_default_avatar=group_default_avatar,  | 
            |
| 67 | 
                + group_from=GroupInfo.TOURGUIDE_GROUP,  | 
            |
| 68 | 
                + started_at=started_at,  | 
            |
| 69 | 
                + ended_at=ended_at,  | 
            |
| 70 | 
                + )  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                + # Redis 群组数据缓存  | 
            |
| 73 | 
                + group_info = set_group_info(group)  | 
            |
| 74 | 
                +  | 
            |
| 75 | 
                + # 群组用户记录创建  | 
            |
| 76 | 
                + GroupUserInfo.objects.create(  | 
            |
| 77 | 
                + group_id=group_id,  | 
            |
| 78 | 
                + user_id=user_id,  | 
            |
| 79 | 
                + nickname=user.final_nickname,  | 
            |
| 80 | 
                + avatar=user.avatar,  | 
            |
| 81 | 
                + admin=True,  | 
            |
| 82 | 
                + user_status=GroupUserInfo.PASSED,  | 
            |
| 83 | 
                + passed_at=tc.utc_datetime(),  | 
            |
| 84 | 
                + subadmin=True,  | 
            |
| 85 | 
                + )  | 
            |
| 86 | 
                +  | 
            |
| 87 | 
                + # Redis 群组用户数据缓存  | 
            |
| 88 | 
                + group_users = set_group_users_info(group)  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                + # Redis 设置导游拥有的导游团  | 
            |
| 91 | 
                + set_tour_guide_own_group(user_id, group_id)  | 
            |
| 92 | 
                +  | 
            |
| 93 | 
                +    return response(200, 'Create Tour Guide Group Success', u'导游团创建成功', {
               | 
            |
| 94 | 
                + 'group_id': group_id,  | 
            |
| 95 | 
                + 'group': group_info,  | 
            |
| 96 | 
                + 'users': group_users,  | 
            |
| 97 | 
                + })  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                +@logit  | 
            |
| 101 | 
                +def tg_group_detail_api(request):  | 
            |
| 102 | 
                + """  | 
            |
| 103 | 
                + 导游团详情  | 
            |
| 104 | 
                + :param request:  | 
            |
| 105 | 
                + :return:  | 
            |
| 106 | 
                + """  | 
            |
| 107 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 108 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 109 | 
                +  | 
            |
| 110 | 
                +    return response(200, 'Get Tour Guide Group Detail Info Success', u'获取导游团详情成功', {
               | 
            |
| 111 | 
                + 'group_id': group_id,  | 
            |
| 112 | 
                + 'group': get_group_info(group_id),  | 
            |
| 113 | 
                + 'users': get_group_users_info(group_id, user_id),  | 
            |
| 114 | 
                + })  | 
            |
| 115 | 
                +  | 
            |
| 116 | 
                +  | 
            |
| 117 | 
                +@logit  | 
            |
| 118 | 
                +def tg_group_update_api(request):  | 
            |
| 119 | 
                + """  | 
            |
| 120 | 
                + 导游团更新  | 
            |
| 121 | 
                + :param request:  | 
            |
| 122 | 
                + :return:  | 
            |
| 123 | 
                + """  | 
            |
| 124 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 125 | 
                +    admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
               | 
            |
| 126 | 
                +    group_name = request.POST.get('group_name', '')
               | 
            |
| 127 | 
                +    group_desc = request.POST.get('group_desc', '')
               | 
            |
| 128 | 
                +  | 
            |
| 129 | 
                +    group_avatar = request.FILES.get('group_avatar', '')
               | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                +    started_at = request.POST.get('started_at', '')
               | 
            |
| 132 | 
                +    ended_at = request.POST.get('ended_at', '')
               | 
            |
| 133 | 
                +  | 
            |
| 134 | 
                + # 群组校验  | 
            |
| 135 | 
                + try:  | 
            |
| 136 | 
                + group = GroupInfo.objects.get(group_id=group_id)  | 
            |
| 137 | 
                + except GroupInfo.DoesNotExist:  | 
            |
| 138 | 
                + return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            |
| 139 | 
                +  | 
            |
| 140 | 
                + # 权限校验  | 
            |
| 141 | 
                + if group.admin_id != admin_id:  | 
            |
| 142 | 
                + return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 143 | 
                +  | 
            |
| 144 | 
                + # 群组名称更新  | 
            |
| 145 | 
                + if group_name:  | 
            |
| 146 | 
                + group.group_name = group_name  | 
            |
| 147 | 
                + # 群组描述更新  | 
            |
| 148 | 
                + if group_desc:  | 
            |
| 149 | 
                + group.group_desc = group_desc  | 
            |
| 150 | 
                + # 群组头像更新  | 
            |
| 151 | 
                + if group_avatar:  | 
            |
| 152 | 
                + _, extension = os.path.splitext(group_avatar.name)  | 
            |
| 153 | 
                +        group_avatar_path = 'group/{uuid}_{extension}'.format(uuid=shortuuid.uuid(), extension=extension)
               | 
            |
| 154 | 
                + if default_storage.exists(group_avatar_path):  | 
            |
| 155 | 
                + default_storage.delete(group_avatar_path)  | 
            |
| 156 | 
                + default_storage.save(group_avatar_path, group_avatar)  | 
            |
| 157 | 
                + group.group_avatar = group_avatar_path  | 
            |
| 158 | 
                + # 起止时间更新  | 
            |
| 159 | 
                + group.started_at = started_at  | 
            |
| 160 | 
                + group.ended_at = ended_at  | 
            |
| 161 | 
                + group.save()  | 
            |
| 162 | 
                +  | 
            |
| 163 | 
                + # Redis 群组数据缓存更新  | 
            |
| 164 | 
                + group_info = set_group_info(group)  | 
            |
| 165 | 
                +  | 
            |
| 166 | 
                +    return response(200, 'Update Group Success', u'群组更新成功', {
               | 
            |
| 167 | 
                + 'group_id': group_id,  | 
            |
| 168 | 
                + 'group': group_info,  | 
            |
| 169 | 
                + 'users': get_group_users_info(group_id, admin_id),  | 
            |
| 170 | 
                + })  | 
            |
| 171 | 
                +  | 
            |
| 172 | 
                +  | 
            |
| 173 | 
                +@logit  | 
            |
| 174 | 
                +def tg_group_close_api(request):  | 
            |
| 175 | 
                + """  | 
            |
| 176 | 
                + 导游团关闭  | 
            |
| 177 | 
                + :param request:  | 
            |
| 178 | 
                + :return:  | 
            |
| 179 | 
                + """  | 
            |
| 180 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 181 | 
                +    admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
               | 
            |
| 182 | 
                +  | 
            |
| 183 | 
                + # 群组校验  | 
            |
| 184 | 
                + try:  | 
            |
| 185 | 
                + group = GroupInfo.objects.get(group_id=group_id)  | 
            |
| 186 | 
                + except GroupInfo.DoesNotExist:  | 
            |
| 187 | 
                + return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            |
| 188 | 
                +  | 
            |
| 189 | 
                + # 权限校验  | 
            |
| 190 | 
                + if group.admin_id != admin_id:  | 
            |
| 191 | 
                + return response(GroupStatusCode.NO_CLOSE_PERMISSION)  | 
            |
| 192 | 
                +  | 
            |
| 193 | 
                + # 群组解锁  | 
            |
| 194 | 
                + group.group_closed = True  | 
            |
| 195 | 
                + group.closed_at = tc.utc_datetime()  | 
            |
| 196 | 
                + group.save()  | 
            |
| 197 | 
                +  | 
            |
| 198 | 
                + # Redis 群组数据缓存更新  | 
            |
| 199 | 
                + set_group_info(group)  | 
            |
| 200 | 
                +  | 
            |
| 201 | 
                + return response(200, u'Close Tour Guide Group Success', u'导游团关闭成功')  | 
            |
| 202 | 
                +  | 
            |
| 203 | 
                +  | 
            |
| 204 | 
                +@logit  | 
            |
| 205 | 
                +def tg_group_gather_start_api(request):  | 
            |
| 206 | 
                + """  | 
            |
| 207 | 
                + 导游团设置集合时间和地点  | 
            |
| 208 | 
                + :param request:  | 
            |
| 209 | 
                + :return:  | 
            |
| 210 | 
                + """  | 
            |
| 211 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 212 | 
                +    admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
               | 
            |
| 213 | 
                +    gather_at = request.POST.get('gather_at', '')
               | 
            |
| 214 | 
                +    gather_lon = request.POST.get('lon', '')  # 经度
               | 
            |
| 215 | 
                +    gather_lat = request.POST.get('lat', '')  # 纬度
               | 
            |
| 216 | 
                +  | 
            |
| 217 | 
                + # 群组校验  | 
            |
| 218 | 
                + try:  | 
            |
| 219 | 
                + group = GroupInfo.objects.get(group_id=group_id)  | 
            |
| 220 | 
                + except GroupInfo.DoesNotExist:  | 
            |
| 221 | 
                + return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            |
| 222 | 
                +  | 
            |
| 223 | 
                + # 权限校验  | 
            |
| 224 | 
                + if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 225 | 
                + return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 226 | 
                +  | 
            |
| 227 | 
                + # 集合信息设置  | 
            |
| 228 | 
                + group.gather_at = gather_at  | 
            |
| 229 | 
                + group.gather_lon = gather_lon  | 
            |
| 230 | 
                + group.gather_lat = gather_lat  | 
            |
| 231 | 
                + group.save()  | 
            |
| 232 | 
                +  | 
            |
| 233 | 
                + # Redis 群组数据缓存更新  | 
            |
| 234 | 
                + set_group_info(group)  | 
            |
| 235 | 
                +  | 
            |
| 236 | 
                + # 更新Session  | 
            |
| 237 | 
                + r.set(TOUR_GUIDE_GROUP_CUR_SESSION, shortuuid.uuid())  | 
            |
| 238 | 
                +  | 
            |
| 239 | 
                + return response(200, u'Set Tour Guide Group Gather Info Success', u'设置导游团集合信息成功')  | 
            
                @@ -0,0 +1,184 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from __future__ import division  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +import json  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +from django.conf import settings  | 
            |
| 8 | 
                +from logit import logit  | 
            |
| 9 | 
                +from TimeConvert import TimeConvert as tc  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +from account.models import UserInfo  | 
            |
| 12 | 
                +from group.models import GroupInfo, GroupUserInfo  | 
            |
| 13 | 
                +from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode  | 
            |
| 14 | 
                +from utils.error.response_utils import response  | 
            |
| 15 | 
                +from utils.group_photo_utils import get_current_photos  | 
            |
| 16 | 
                +from utils.redis.rgroup import get_group_info, get_group_users_info, set_group_users_info  | 
            |
| 17 | 
                +from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET,  | 
            |
| 18 | 
                + GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_SESSION,  | 
            |
| 19 | 
                + TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_USER_GEO_LIST)  | 
            |
| 20 | 
                +from utils.redis.rtourguide import get_tour_guide_own_group  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                +r = settings.REDIS_CACHE  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                +  | 
            |
| 26 | 
                +@logit  | 
            |
| 27 | 
                +def tgu_group_user_join_api(request):  | 
            |
| 28 | 
                + """  | 
            |
| 29 | 
                + 导游团用户加群  | 
            |
| 30 | 
                + :param request:  | 
            |
| 31 | 
                + :return:  | 
            |
| 32 | 
                + """  | 
            |
| 33 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识,识别二维码获取
               | 
            |
| 34 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 35 | 
                +    nickname = request.POST.get('nickname', '')
               | 
            |
| 36 | 
                +  | 
            |
| 37 | 
                + # 获取导游团唯一标识  | 
            |
| 38 | 
                + group_id = get_tour_guide_own_group(admin_id)  | 
            |
| 39 | 
                +  | 
            |
| 40 | 
                + # 用户校验  | 
            |
| 41 | 
                + try:  | 
            |
| 42 | 
                + user = UserInfo.objects.get(user_id=user_id)  | 
            |
| 43 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 44 | 
                + return response(UserStatusCode.USER_NOT_FOUND)  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                + # 群组校验  | 
            |
| 47 | 
                + try:  | 
            |
| 48 | 
                + group = GroupInfo.objects.get(group_id=group_id)  | 
            |
| 49 | 
                + except GroupInfo.DoesNotExist:  | 
            |
| 50 | 
                + return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            |
| 51 | 
                +  | 
            |
| 52 | 
                + # 群组锁定校验  | 
            |
| 53 | 
                + if group.group_lock:  | 
            |
| 54 | 
                + return response(GroupStatusCode.GROUP_HAS_LOCKED)  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                + # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新  | 
            |
| 57 | 
                + group_user, created = GroupUserInfo.objects.get_or_create(  | 
            |
| 58 | 
                + group_id=group_id,  | 
            |
| 59 | 
                + user_id=user_id,  | 
            |
| 60 | 
                + )  | 
            |
| 61 | 
                + if group_user.user_status != GroupUserInfo.PASSED:  | 
            |
| 62 | 
                + group_user.current_id = -1 if group.group_from == GroupInfo.SESSION_GROUP else int(  | 
            |
| 63 | 
                + r.get(GROUP_LAST_PHOTO_PK % group_id) or -1)  | 
            |
| 64 | 
                + group_user.nickname = nickname or user.final_nickname  | 
            |
| 65 | 
                + group_user.avatar = user.avatar  | 
            |
| 66 | 
                + # group_user.admin = False # Admin Field Default False, Should Not Assign  | 
            |
| 67 | 
                + group_user.user_status = GroupUserInfo.PASSED  | 
            |
| 68 | 
                + group_user.passed_at = tc.utc_datetime()  | 
            |
| 69 | 
                + group_user.save()  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                + # Redis 群组用户数据缓存  | 
            |
| 72 | 
                + set_group_users_info(group)  | 
            |
| 73 | 
                +  | 
            |
| 74 | 
                + # Redis 群组通过集合缓存  | 
            |
| 75 | 
                + r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id)  | 
            |
| 76 | 
                + r.srem(GROUP_USERS_DELETED_SET % group_id, user_id)  | 
            |
| 77 | 
                + r.srem(GROUP_USERS_QUIT_SET % group_id, user_id)  | 
            |
| 78 | 
                + r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + curinfo = get_current_photos(group_id, user_id, group_user.current_id)  | 
            |
| 81 | 
                +  | 
            |
| 82 | 
                +    return response(200, 'Apply Success', u'申请成功', {
               | 
            |
| 83 | 
                +        'current_id': curinfo.get('current_id', ''),
               | 
            |
| 84 | 
                +        'photos': curinfo.get('photos', ''),
               | 
            |
| 85 | 
                + 'group_id': group_id,  | 
            |
| 86 | 
                + 'group': get_group_info(group_id),  | 
            |
| 87 | 
                + 'user_id': user_id,  | 
            |
| 88 | 
                + 'users': get_group_users_info(group_id, user_id),  | 
            |
| 89 | 
                + })  | 
            |
| 90 | 
                +  | 
            |
| 91 | 
                +  | 
            |
| 92 | 
                +@logit  | 
            |
| 93 | 
                +def tgu_group_user_update_api(request):  | 
            |
| 94 | 
                + """  | 
            |
| 95 | 
                + 导游团用户更新  | 
            |
| 96 | 
                + :param request:  | 
            |
| 97 | 
                + :return:  | 
            |
| 98 | 
                + """  | 
            |
| 99 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 100 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            |
| 101 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                +    name = request.POST.get('name', '')
               | 
            |
| 104 | 
                +    phone = request.POST.get('phone', '')
               | 
            |
| 105 | 
                +    relative_person = request.POST.get('relative_person', '')
               | 
            |
| 106 | 
                +    remark = request.POST.get('remark', '')
               | 
            |
| 107 | 
                +  | 
            |
| 108 | 
                + # 群组校验  | 
            |
| 109 | 
                + try:  | 
            |
| 110 | 
                + group = GroupInfo.objects.get(group_id=group_id)  | 
            |
| 111 | 
                + except GroupInfo.DoesNotExist:  | 
            |
| 112 | 
                + return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            |
| 113 | 
                +  | 
            |
| 114 | 
                + # 权限校验  | 
            |
| 115 | 
                + if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 116 | 
                + return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 117 | 
                +  | 
            |
| 118 | 
                + try:  | 
            |
| 119 | 
                + group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True)  | 
            |
| 120 | 
                + except GroupUserInfo.DoesNotExist:  | 
            |
| 121 | 
                + return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)  | 
            |
| 122 | 
                +  | 
            |
| 123 | 
                + # 用户信息更新  | 
            |
| 124 | 
                + # TODO: Whether sync name and phone to UserInfo or not?  | 
            |
| 125 | 
                + group_user.name = name  | 
            |
| 126 | 
                + group_user.phone = phone  | 
            |
| 127 | 
                + group_user.relative_person = relative_person  | 
            |
| 128 | 
                + group_user.remark = remark  | 
            |
| 129 | 
                + group_user.save()  | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                + # Redis 群组用户数据缓存  | 
            |
| 132 | 
                + group_users = set_group_users_info(group)  | 
            |
| 133 | 
                +  | 
            |
| 134 | 
                +    return response(200, 'Update Group Success', u'群组更新成功', {
               | 
            |
| 135 | 
                + 'group_id': group_id,  | 
            |
| 136 | 
                + 'group': group.data,  | 
            |
| 137 | 
                + 'users': group_users,  | 
            |
| 138 | 
                + })  | 
            |
| 139 | 
                +  | 
            |
| 140 | 
                +  | 
            |
| 141 | 
                +@logit  | 
            |
| 142 | 
                +def tgu_group_user_locations_api(request):  | 
            |
| 143 | 
                + """  | 
            |
| 144 | 
                + 导游团所有用户位置信息  | 
            |
| 145 | 
                + :param request:  | 
            |
| 146 | 
                + :return:  | 
            |
| 147 | 
                + """  | 
            |
| 148 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 149 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            |
| 150 | 
                +  | 
            |
| 151 | 
                + # 权限校验  | 
            |
| 152 | 
                + if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 153 | 
                + return response(GroupStatusCode.NO_LOCATION_PERMISSION)  | 
            |
| 154 | 
                +  | 
            |
| 155 | 
                +    return response(200, 'Get Tour Guide Group All User Location Success', u'获取导游团用户地理位置信息成功', {
               | 
            |
| 156 | 
                + 'group_id': group_id,  | 
            |
| 157 | 
                + 'locations': r.georadius(TOUR_GUIDE_GROUP_GEO_INFO % group_id, 0, 0, '+inf', unit='m', withdist=True, withcoord=True, sort='ASC')  | 
            |
| 158 | 
                + # 'locations': [['x', 0.33, (2.68220901489e-06, 1.26736058093e-06)]]  | 
            |
| 159 | 
                + })  | 
            |
| 160 | 
                +  | 
            |
| 161 | 
                +  | 
            |
| 162 | 
                +@logit  | 
            |
| 163 | 
                +def tgu_group_user_location_api(request):  | 
            |
| 164 | 
                + """  | 
            |
| 165 | 
                + 导游团单个用户位置信息  | 
            |
| 166 | 
                + :param request:  | 
            |
| 167 | 
                + :return:  | 
            |
| 168 | 
                + """  | 
            |
| 169 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 170 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            |
| 171 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 172 | 
                +  | 
            |
| 173 | 
                + # 权限校验  | 
            |
| 174 | 
                + if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 175 | 
                + return response(GroupStatusCode.NO_LOCATION_PERMISSION)  | 
            |
| 176 | 
                +  | 
            |
| 177 | 
                + session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)  | 
            |
| 178 | 
                + locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1)  | 
            |
| 179 | 
                +  | 
            |
| 180 | 
                +    return response(200, 'Get Tour Guide Group User Location Success', u'获取导游团用户地理位置信息成功', {
               | 
            |
| 181 | 
                + 'group_id': group_id,  | 
            |
| 182 | 
                + 'user_id': user_id,  | 
            |
| 183 | 
                + 'locations': [json.loads(loc) for loc in locations]  | 
            |
| 184 | 
                + })  | 
            
                @@ -46,6 +46,7 @@ INSTALLED_APPS = (  | 
            ||
| 46 | 46 | 
                'django_q',  | 
            
| 47 | 47 | 
                'api',  | 
            
| 48 | 48 | 
                'account',  | 
            
| 49 | 
                + 'geo',  | 
            |
| 49 | 50 | 
                'group',  | 
            
| 50 | 51 | 
                'message',  | 
            
| 51 | 52 | 
                'operation',  | 
            
                @@ -54,26 +54,34 @@ class PhotoStatusCode(BaseStatusCode):  | 
            ||
| 54 | 54 | 
                 | 
            
| 55 | 55 | 
                 | 
            
| 56 | 56 | 
                class GroupStatusCode(BaseStatusCode):  | 
            
| 57 | 
                - """ 群组相关错误码 4020xx """  | 
            |
| 57 | 
                + """ 群组/团相关错误码 4020xx """  | 
            |
| 58 | 58 | 
                GROUP_NOT_FOUND = StatusCodeField(402001, u'Group Not Found', description=u'群组不存在')  | 
            
| 59 | 59 | 
                GROUP_HAS_LOCKED = StatusCodeField(402002, u'Group Has Locked', description=u'群组已锁定')  | 
            
| 60 | 60 | 
                NOT_GROUP_ADMIN = StatusCodeField(402003, u'Not Group Admin', description=u'非群组管理员')  | 
            
| 61 | 
                - NO_UPDATE_PERMISSION = StatusCodeField(402004, u'No Update Permission', description=u'没有更新权限')  | 
            |
| 62 | 
                - NO_LOCK_PERMISSION = StatusCodeField(402005, u'No Lock Permission', description=u'没有锁定权限')  | 
            |
| 63 | 
                - NO_UNLOCK_PERMISSION = StatusCodeField(402006, u'No Unlock Permission', description=u'没有解锁权限')  | 
            |
| 64 | 
                - NO_REMOVE_PERMISSION = StatusCodeField(402007, u'No Remove Permission', description=u'没有移除权限')  | 
            |
| 65 | 
                - NO_QUIT_PERMISSION = StatusCodeField(402008, u'No Quit Permission', description=u'没有退出权限')  | 
            |
| 66 | 
                - NO_PASS_PERMISSION = StatusCodeField(402009, u'No Pass Permission', description=u'没有通过权限')  | 
            |
| 67 | 
                - NO_REFUSE_PERMISSION = StatusCodeField(402010, u'No Refuse Permission', description=u'没有拒绝权限')  | 
            |
| 68 | 
                - DUPLICATE_JOIN_REQUEST = StatusCodeField(402011, u'Duplicate Join Request', description=u'重复加群申请')  | 
            |
| 69 | 
                - JOIN_REQUEST_NOT_FOUND = StatusCodeField(402012, u'Join Request Not Found', description=u'加群申请不存在')  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                + NO_UPDATE_PERMISSION = StatusCodeField(402010, u'No Update Permission', description=u'没有更新权限')  | 
            |
| 63 | 
                + NO_LOCK_PERMISSION = StatusCodeField(402011, u'No Lock Permission', description=u'没有锁定权限')  | 
            |
| 64 | 
                + NO_UNLOCK_PERMISSION = StatusCodeField(402012, u'No Unlock Permission', description=u'没有解锁权限')  | 
            |
| 65 | 
                + NO_REMOVE_PERMISSION = StatusCodeField(402013, u'No Remove Permission', description=u'没有移除权限')  | 
            |
| 66 | 
                + NO_QUIT_PERMISSION = StatusCodeField(402014, u'No Quit Permission', description=u'没有退出权限')  | 
            |
| 67 | 
                + NO_PASS_PERMISSION = StatusCodeField(402015, u'No Pass Permission', description=u'没有通过权限')  | 
            |
| 68 | 
                + NO_REFUSE_PERMISSION = StatusCodeField(402016, u'No Refuse Permission', description=u'没有拒绝权限')  | 
            |
| 69 | 
                + NO_CLOSE_PERMISSION = StatusCodeField(402017, u'No Close Permission', description=u'没有关闭权限')  | 
            |
| 70 | 
                + NO_LOCATION_PERMISSION = StatusCodeField(402018, u'No Location Permission', description=u'没有地理位置权限')  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                + DUPLICATE_JOIN_REQUEST = StatusCodeField(402020, u'Duplicate Join Request', description=u'重复加群申请')  | 
            |
| 73 | 
                + JOIN_REQUEST_NOT_FOUND = StatusCodeField(402021, u'Join Request Not Found', description=u'加群申请不存在')  | 
            |
| 74 | 
                +  | 
            |
| 75 | 
                + COULD_HAVE_ONLY_ONE_ACTIVE_GROUP = StatusCodeField(402030, u'Could Have Only One Active Group', description=u'只能创建一个活跃团')  | 
            |
| 70 | 76 | 
                 | 
            
| 71 | 77 | 
                 | 
            
| 72 | 78 | 
                class GroupUserStatusCode(BaseStatusCode):  | 
            
| 73 | 
                - """ 群组用户相关错误码 4021xx """  | 
            |
| 79 | 
                + """ 群组/团用户相关错误码 4021xx """  | 
            |
| 74 | 80 | 
                GROUP_USER_NOT_FOUND = StatusCodeField(402101, u'Group User Not Found', description=u'群组用户不存在')  | 
            
| 75 | 81 | 
                GROUP_USER_HAS_DELETED = StatusCodeField(402102, u'Group User Has Deleted', description=u'群组用户被移除')  | 
            
| 76 | 82 | 
                 | 
            
| 83 | 
                + USER_HAS_NOT_JOIN_GROUP = StatusCodeField(402131, u'User Has Not Join Group', description=u'用户未加入导游团')  | 
            |
| 84 | 
                +  | 
            |
| 77 | 85 | 
                 | 
            
| 78 | 86 | 
                class GroupPhotoStatusCode(BaseStatusCode):  | 
            
| 79 | 87 | 
                """ 群组照片(飞图)相关错误码 4022xx """  | 
            
                @@ -6,6 +6,14 @@ UUID_LIST = 'uuid:list' # List, 唯一标识列表  | 
            ||
| 6 | 6 | 
                # 用户相关  | 
            
| 7 | 7 | 
                PROFILE_INFO = 'profile:info:%s' # STRING,用户信息,user_id  | 
            
| 8 | 8 | 
                 | 
            
| 9 | 
                +# 导游相关  | 
            |
| 10 | 
                +TOUR_GUIDE_GROUP_GEO_INFO = 'tour:guide:group:geo:info:%s' # ZSET,旅游团地理位置信息,group_id  | 
            |
| 11 | 
                +TOUR_GUIDE_GROUP_CUR_SESSION = 'tour:guide:group:cur:session:%s' # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新  | 
            |
| 12 | 
                +TOUR_GUIDE_GROUP_USER_GEO_LIST = 'tour:guide:group:user:geo:list:%s:%s:%s' # LIST,旅游团当前用户地理位置列表,group_id、session_id、user_id  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +TOUR_GUIDE_GROUP_USER_OWN = 'tour:guide:group:user:own:%s' # STRING,导游当前拥有的导游团,user_id,导游创建导游团的时候更新  | 
            |
| 15 | 
                +TOUR_GUIDE_GROUP_USER_BELONG = 'tour:guide:group:user:belong:%s' # STRING,用户当前所属导游团,user_id,用户加入导游团的时候更新  | 
            |
| 16 | 
                +  | 
            |
| 9 | 17 | 
                # 群组相关  | 
            
| 10 | 18 | 
                GROUP_INFO = 'group:info:%s' # STRING,群组信息,group_id  | 
            
| 11 | 19 | 
                 | 
            
                @@ -0,0 +1,21 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from django.conf import settings  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from utils.redis.rkeys import TOUR_GUIDE_GROUP_USER_OWN  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +r = settings.REDIS_CACHE  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                +# 导游相关  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                +def set_tour_guide_own_group(user_id, group_id):  | 
            |
| 15 | 
                + """ 设置导游拥有的导游团 """  | 
            |
| 16 | 
                + r.set(TOUR_GUIDE_GROUP_USER_OWN % user_id, group_id)  | 
            |
| 17 | 
                +  | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                +def get_tour_guide_own_group(user_id):  | 
            |
| 20 | 
                + """ 获取导游拥有的导游团 """  | 
            |
| 21 | 
                + return r.get(TOUR_GUIDE_GROUP_USER_OWN % user_id)  |